package cppcloud

import (
	"encoding/json"
	"fmt"
	"os/exec"
	"runtime"
	"time"
	"tool"
)

// cppcloud_serv的go客户端sdk主要类，
//   负责接收处理相关的业务（譬如，接收关闭通知，响应存活检测等）

type CloudApp struct {
	*TCPClient
	confInstance    *CloudConf
	svrStatInstance *SvrStat
}

// CreateCppCloudApp 创建CppCloud的go-sdk客户端对象
func CreateCppCloudApp(svrAddr string, attrMap map[string]interface{}, timoSec int) *CloudApp {
	tcli := MakeTCPClient(svrAddr, attrMap, timoSec)
	if nil == tcli {
		return nil
	}

	ret := &CloudApp{tcli, nil, nil}
	var thisHandle MessageHandle = ret
	ret.SetCMDHandler(CMD_KEEPALIVE_REQ, 0, &thisHandle, false)
	ret.SetCMDHandler(CMD_KEEPALIVE_RSP, 0, &thisHandle, false)
	ret.SetCMDHandler(CMD_EVNOTIFY_REQ, 0, &thisHandle, false)

	// 设置通告回调处理
	ret.AddNotifyCallBack("check-alive", ret.onChkAlive)
	ret.AddNotifyCallBack("exit", ret.onExit)
	ret.AddNotifyCallBack("shellcmd", ret.onShellcmd)
	ret.AddNotifyCallBack("iostat", ret.onIOstat)
	ret.AddNotifyCallBack("aliasname", ret.onSetAliasName)
	ret.svrStatInstance = CreateSvrStat(ret)
	// ret.AddNotifyCallBack("connected", xxx, False)
	// ret.AddNotifyCallBack("cfg_change", .)

	return ret
}

func (capp *CloudApp) ConfInstance(listfname ...string) (cnf *CloudConf, err string) {
	if nil != capp.confInstance {
		return capp.confInstance, ""
	}

	cnf, err = createCloudConf(capp, listfname...)
	if nil != cnf {
		capp.confInstance = cnf
	} else {
		fmt.Println("NEWCONFFAIL|", err)
	}
	return
}

// SvrStatInstance 返回服务统计对象
func (capp *CloudApp) SvrStatInstance() *SvrStat {
	return capp.svrStatInstance
}

// ProcessMessage  内置消息处理方法，处理一些常规操作
func (capp *CloudApp) ProcessMessage(errCode int, cmdid, seqid uint16, bodystr string) *MessageData {
	switch cmdid {
	case CMD_KEEPALIVE_REQ:
		return &MessageData{CMD_KEEPALIVE_RSP, seqid, ""}
	case CMD_KEEPALIVE_RSP:
		break
	case CMD_EVNOTIFY_REQ: // 处理通告消息
		dict := map[string]interface{}{}
		json.Unmarshal([]byte(bodystr), &dict)
		notify, _ := tool.JSONGetString(dict, "notify")
		from, _ := tool.JSONGetInt(dict, "from")
		code, result := capp.invokeCallBack(notify, dict)

		if from > 0 {
			return &MessageData{
				(cmdid | CMDID_MID), seqid,
				map[string]interface{}{
					"code":   code,
					"to":     from,
					"result": result,
					"notify": notify,
				}}
		}

	}

	return nil
}

func (capp *CloudApp) onChkAlive(map[string]interface{}) (code int, result interface{}) {
	return 0, time.Now().Unix()
}

func (capp *CloudApp) onExit(map[string]interface{}) (code int, result interface{}) {
	go func() {
		time.Sleep(1)
		capp.svrStatInstance.shutdown()
		capp.Shutdown()
	}()
	return 0, "closing"
}

func (capp *CloudApp) onShellcmd(param map[string]interface{}) (code int, result interface{}) {
	if "linux" == runtime.GOOS {
		shellcmdarr := [3]string{"uptime", "free -h", "df -h"}
		shellcmdid, ok := tool.JSONGetInt(param, "cmdid")
		if ok && shellcmdid > 0 && shellcmdid < len(shellcmdarr)+1 {
			return 0, runShellCmd(shellcmdarr[shellcmdid-1])
		} else {
			return 1, "cmdid invalid"
		}
	}
	return 0, "未实现"
}

func runShellCmd(command string) string {
	cmd := exec.Command("sh", "-c", command)
	if result, err := cmd.Output(); err == nil {
		return string(result)
	} else {
		return err.Error()
	}
}

func (capp *CloudApp) onSetAliasName(param map[string]interface{}) (code int, result interface{}) {
	aliasname, _ := tool.JSONGetString(param, "aliasname")
	capp.RequestNoWait(CMD_SETARGS_REQ, map[string]interface{}{"aliasname": aliasname})
	return 0, "ok"
}

func (capp *CloudApp) onIOstat(map[string]interface{}) (code int, result interface{}) {
	return 0, map[string]interface{}{
		"all": [4]int64{capp.stat.RecvBytes, capp.stat.SendBytes, capp.stat.RecvPkgn, capp.stat.SendPkgn},
	}
}
